import os, sys, shutil
import cfg
import tarfile
from helpers import DirStack, substitute, checkexists

def get_deb_templates(custom_deb_templates):
    default_deb_templates = {
        'changelog': cfg.TEMPLATES_DIR + '/debian/changelog.template',
        'compat': cfg.TEMPLATES_DIR + '/debian/compat.template',
        'control': cfg.TEMPLATES_DIR + '/debian/control.template',
        'copyright': cfg.TEMPLATES_DIR + '/debian/copyright.template',
        'dirs': cfg.TEMPLATES_DIR + '/debian/dirs.template',
        'docs': cfg.TEMPLATES_DIR + '/debian/docs.template',
        'rules': cfg.TEMPLATES_DIR + '/debian/rules.template',
    }

    deb_templates = default_deb_templates

    if custom_deb_templates:
        for k, v in custom_deb_templates.items():
            deb_templates[k] = v.replace('%PRESETS%', cfg.TEMPLATES_DIR + '/presets')

    checkexists(deb_templates.values())

    return deb_templates


def build_package(info, src_files, custom_deb_templates=None, delete_workfiles=True,
    dereference=True #  don't dump symlinks; dump the files they point to
):
    """
    Debianization.
    Builds debian package.
    """
    root_dir = os.path.realpath(info.build.sources_dir)

    dir_stack = DirStack()
    dir_stack.pushd(root_dir)

    deb_templates = get_deb_templates(custom_deb_templates)

    fake_root = 'buildroot'
    work_dir = '%s/%s-%s' % (fake_root, info.deb_package_name, info.version)

    def clean():
        if os.path.exists(fake_root):
            shutil.rmtree(fake_root)
    clean()

    build_root = '%s/debian/%s/%s' % (work_dir, info.deb_package_name, info.install_dir)
    os.makedirs(build_root)

    dirs = []
    if info.install_dir not in dirs:
        dirs.append(info.install_dir)

    replaces = {
        '%CHANGELOG%': info.changelog_core,
        '%DIRS%': '\n'.join(dirs),
    }

    replaces.update(info.get_replaces())

    if not os.path.exists('%s/debian' % work_dir):
        os.makedirs('%s/debian' % work_dir)

    for file, src in deb_templates.items():
        dest = '%s/debian/%s' % (work_dir, file)
        dest_dir = os.path.dirname(dest)
        if dest_dir and not os.path.exists(dest_dir):
            os.makedirs(dest_dir)
        substitute(src, dest, replaces)

    os.system('chmod 0777 %s/debian/rules' % work_dir)

    checkexists(src_files)

    # if src_files has dirs -- tar pack all dirs content too.
    files, empty_dirs = split_filelist(src_files)
    process_src_files(files, build_root, dereference)

    # TODO make anything with empty_dirs ("mkdir -p" in postinstall?)
    print 'Warning: empty dirs not archived (add this directories to dirs.template for example):'
    print ''.join(' * %s\n' % d for d in empty_dirs)

    dir_stack.pushd(work_dir)

    result = os.system('dpkg-buildpackage -us -uc -b -rfakeroot')
    if result:
        print "Build failed."
        sys.exit(result)

    dir_stack.popd()

    os.system('mv %s/%s*deb %s' % (fake_root, info.deb_package_name, root_dir))

    if delete_workfiles:
        clean()

    dir_stack.popd()


def process_src_files(src_files, build_root, dereference):
    archive_name = create_archive(src_files, dereference)
    deploy_archive(archive_name, build_root)
    if os.path.exists(archive_name):
        os.remove(archive_name)

def split_filelist(src_files):
    """
    Split list of pathes to list of pathes to files and
    list of empty directories pathes.
    """
    src_files_basedirs = set(os.path.dirname(f).rstrip('/') for f in src_files)
    files, empty_dirs = [], []
    for p in src_files:
        if os.path.isdir(p) and not os.path.islink(p):
            if p.rstrip('/') not in src_files_basedirs:
                empty_dirs.append(p)
#            print '# empty: %s' % p
        else:
            files.append(p)

    return files, empty_dirs

def create_archive(src_files, dereference=True):
    archive_name = 'sources.tar'
    tf = tarfile.TarFile(archive_name, 'w')
    tf.dereference = dereference
    for f in src_files:
        tf.add(f)
    tf.close()
    return archive_name

def deploy_archive(archive_name, build_root):
    if not os.path.exists(build_root):
        os.makedirs(build_root)

    deploed_archive_path = '%s/%s' % (build_root, archive_name)
    shutil.copyfile(archive_name, deploed_archive_path)

    cmd = 'tar -C %s -xf %s' % (build_root, deploed_archive_path)
    if os.system(cmd):
        raise Exception('Command %s can not be executed' % cmd)

    os.remove(deploed_archive_path)
